<template>
  <component
    class="w-button"
    :is="route ? 'a' : 'button'"
    :type="!route && type"
    :href="(route && (externalLink ? route : resolvedRoute)) || null"
    :class="classes"
    :disabled="!!disabled || null"
    v-on="listeners"
    :style="styles"
  >
    <w-icon v-if="icon">{{ icon }}</w-icon>
    <slot v-else></slot>
    <transition name="scale-fade">
      <div class="w-button__loader" v-if="loading">
        <slot name="loading"
          ><svg viewBox="0 0 40 40">
            <circle
              cx="20"
              cy="20"
              r="18"
              fill="transparent"
              stroke="currentColor"
              stroke-width="4"
              stroke-linecap="round"
            ></circle>
          </svg>
        </slot>
      </div>
    </transition>
  </component>
</template>

<script>
import { computed, getCurrentInstance } from "vue";
export default {
  name: "w-button",

  props: {
    color: { type: String },
    bgColor: { type: String },
    dark: { type: Boolean },
    outline: { type: Boolean },
    text: { type: Boolean },
    round: { type: Boolean },
    shadow: { type: Boolean },
    tile: { type: Boolean },
    route: { type: [String, Object] }, // Creates a link.
    // Force use of `a` instead of router-link.
    // Router link does not go to a url starting with `#` with history mode.
    forceLink: { type: Boolean },
    type: { type: String, default: "button" },
    disabled: { type: Boolean },
    loading: { type: Boolean },
    // If an icon is passed, no text will display.
    icon: { type: String, default: null },
    // Positions.
    absolute: { type: Boolean },
    fixed: { type: Boolean },
    top: { type: Boolean },
    bottom: { type: Boolean },
    left: { type: Boolean },
    right: { type: Boolean },
    zIndex: { type: [Number, String] },
    // Sizes.
    width: { type: [Number, String] },
    height: { type: [Number, String] },
    xs: { type: Boolean },
    sm: { type: Boolean },
    md: { type: Boolean },
    lg: { type: Boolean },
    xl: { type: Boolean }
  },

  emits: [],

  setup(props) {
    const instance = getCurrentInstance();
    const hasRouter = computed(() => {
      return "$router" in instance.ctx;
    });
    const resolvedRoute = computed(() => {
      return hasRouter.value
        ? instance.ctx.$router.resolve(props.route).href
        : props.route;
    });
    const listeners = computed(() => {
      // If the button is a router-link, we can't apply events on it since vue-router needs the .native
      // modifier but it's not available with the v-on directive.
      // So do a manual router.push if $router is present.
      return props.route && hasRouter.value && !props.forceLink
        ? {
            ...instance.ctx.$attrs,
            click: e => {
              if (instance.ctx.$attrs.click) instance.ctx.$attrs.click(e);

              instance.ctx.$router.push(props.route);
              e.stopPropagation(); // If going to a route, no need to bubble up the event.
              e.preventDefault();
            }
          }
        : instance.ctx.$attrs;
    });
    const size = computed(() => {
      return (
        (props.xs && "xs") ||
        (props.sm && "sm") ||
        (props.lg && "lg") ||
        (props.xl && "xl") ||
        "md"
      );
    });
    const position = computed(() => {
      return [
        (props.top && "top") || (props.bottom && "bottom") || "top",
        (props.left && "left") || (props.right && "right") || "right"
      ];
    });
    const externalLink = computed(() => {
      return /^(https?:)?\/\//.test(props.route);
    });
    const classes = computed(() => {
      return {
        // If no color / bg color is set, set a primary color by default.
        "primary--bg":
          !props.bgColor &&
          !props.color &&
          !props.dark &&
          !(props.outline || props.text),
        primary:
          !props.bgColor &&
          !props.color &&
          !props.dark &&
          (props.outline || props.text),

        [props.color]: props.color,
        [`${props.bgColor}--bg`]: props.bgColor,
        "w-button--dark": props.dark && !props.outline,
        "w-button--outline": props.outline,
        "w-button--text": props.text,
        "w-button--round": props.round,
        "w-button--tile": props.tile,
        "w-button--shadow": props.shadow,
        "w-button--loading": props.loading,
        "w-button--icon": props.icon,
        [`size--${size.value}`]: true,
        "w-button--absolute": props.absolute,
        "w-button--fixed": props.fixed,
        [`w-button--${position.value.join(" w-button--")}`]:
          props.absolute || props.fixed
      };
    });
    const styles = computed(() => {
      return {
        width: (!isNaN(props.width) ? `${props.width}px` : props.width) || null,
        height:
          (!isNaN(props.height) ? `${props.height}px` : props.height) || null,
        zIndex: props.zIndex || props.zIndex === 0 || null
      };
    });
    return {
      hasRouter,
      resolvedRoute,
      listeners,
      size,
      position,
      externalLink,
      classes,
      styles
    };
  }

};
</script>
